package com.tianji.learning.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.cache.CategoryCache;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CategoryClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.client.search.SearchClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CategoryBasicDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.QuestionFormDTO;
import com.tianji.learning.domain.po.InteractionQuestion;
import com.tianji.learning.domain.po.InteractionReply;
import com.tianji.learning.domain.query.QuestionAdminPageQuery;
import com.tianji.learning.domain.query.QuestionPageQuery;
import com.tianji.learning.domain.vo.QuestionAdminVO;
import com.tianji.learning.domain.vo.QuestionVO;
import com.tianji.learning.enums.QuestionStatus;
import com.tianji.learning.mapper.InteractionQuestionMapper;
import com.tianji.learning.service.IInteractionQuestionService;
import com.tianji.learning.service.IInteractionReplyService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * <p>
 * 互动提问的问题表 服务实现类
 * </p>
 *
 * @author author
 * @since 2025-04-02
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class InteractionQuestionServiceImpl extends ServiceImpl<InteractionQuestionMapper, InteractionQuestion> implements IInteractionQuestionService {
    private final IInteractionReplyService replyService;
    private final UserClient userClient;
    private final SearchClient searchClient;
    private final CourseClient courseClient;
    private final CategoryClient categoryClient;
    private final CatalogueClient catalogueClient;
    private final CategoryCache categoryCache;

    @Override
    public void addQuestion(QuestionFormDTO form) {
        //1.获取当前登录用户id
        Long userId = UserContext.getUser();
        //2.将dto转化为po
        InteractionQuestion question = BeanUtil.copyProperties(form, InteractionQuestion.class);
        //3.保存到数据库中
        //3.1.设置用户id
        question.setUserId(userId);
        boolean save = save(question);
        if (!save){
            throw new RuntimeException("保存问题失败");
        }
        log.info("新增问题成功");
    }

    @Override
    public void updateQuestion(Long id, QuestionFormDTO form) {
        //1.做健壮性判断
        if (form.getTitle().isBlank() || form.getDescription().isBlank() || form.getAnonymity()==null){
            throw new RuntimeException("问题标题、描述、匿名不能为空");
        }
        //2.根据问题id从问题表中查询数据
        InteractionQuestion byId = this.getById(id);
        if (byId==null){
            throw new RuntimeException("要修改的问题不存在");
        }
        //3.赋值
        byId.setTitle(form.getTitle());
        byId.setDescription(form.getDescription());
        byId.setAnonymity(form.getAnonymity());
        //4.更新数据库
        boolean update = updateById(byId);
        if (!update){
            throw new RuntimeException("更新问题失败");
        }
    }

    @Override
    public PageDTO<QuestionVO> queryQuestionByPage(QuestionPageQuery query) {
        /**
         * 总结：在分页查询互动问题时，可以没有问题，也可以没有最新评论所以后面的关于userIds以及最新评论ids可以为空，当这些为空时则不封装到vo对象中返回，
         * 使用在封装前要进行非空判断，否则会报空指针异常
         * 因为要返回前端提问者昵称，提问者头像，以及最近一次回答用户的昵称和评论
         * 1.所以这里我们通过采用stream流获取每一个问题的最新一次回答ids集合，再通过远程调用查询互动评论表中的数据，将其转为map<ids,InteractionReply>,
         * 但在封装vo对象时应该对map集合进行非空判断，否则会报空指针异常，后面在对record循环遍历时，通过远程调用获取用户微服务获取最近一次回答用户的昵称
         * 2.这里我们通过stream流获取提问者用户id集合，通过远程调用查询用户微服务，将其转为map<userIds,UserDTO>，再封装到vo对象中返回，封装前要对userId进行非空判断，否则会报空指针异常
         * */
        //1.做健壮性判断，courseId是必须要有的
        if (query.getCourseId()==null){
           throw new BadRequestException("课程id不能为空");
        }
        //2.获取当前登录用户id
        Long userId = UserContext.getUser();
        //3.分页查询互动问题表 必须：userId=? , courseId=?  不必须：onlyMine=? , , sectionId=? 隐藏条件：hidden=?
        Page<InteractionQuestion> page = this.lambdaQuery()
                .select(InteractionQuestion.class, new Predicate<TableFieldInfo>() {
                    @Override
                    public boolean test(TableFieldInfo tableFieldInfo) {
                        return !tableFieldInfo.getProperty().equals("description");
                    }
                })//排除description字段
                .eq(query.getOnlyMine(),InteractionQuestion::getUserId, userId)
                .eq(InteractionQuestion::getCourseId, query.getCourseId())
                .eq(query.getSectionId() != null, InteractionQuestion::getSectionId, query.getSectionId())
                .eq(InteractionQuestion::getHidden, false)
                .page(query.toMpPageDefaultSortByCreateTimeDesc());
        List<InteractionQuestion> records = page.getRecords();
        if (CollUtils.isEmpty(records)){
            return PageDTO.empty(page);
        }
        //3.1通过stream获取互动问题最新id集合->latestAnswerId
        Set<Long> aIds = records.stream().filter(c -> c.getLatestAnswerId()!=null).map(InteractionQuestion::getLatestAnswerId).collect(Collectors.toSet());
        //3.2通过stream流获取提出问题的用户id集合
        Set<Long> userIds = records.stream().filter(c -> !c.getAnonymity()).map(InteractionQuestion::getUserId).collect(Collectors.toSet());
        //4.根据latestAnswerId查询回复表的最新回答 隐藏字段不需要查询
        List<InteractionReply> list=new ArrayList<>();
        if (CollUtils.isNotEmpty(aIds)) {
             list= replyService.list(Wrappers.<InteractionReply>lambdaQuery()
                     .in(InteractionReply::getId, aIds)
                     .eq(InteractionReply::getHidden, false));
        }
        //4.1将list转为map<latestAnswerId,>
        Map<Long, InteractionReply> map = list.stream()
                .collect(Collectors.toMap(InteractionReply::getId, reply -> reply));
        if (CollUtils.isEmpty(map)){
            log.info("还没有人回答这个问题回答");
        }
        //5.远程调用用户服务，得到提问者的用户昵称和头像
        List<UserDTO> users = userClient.queryUserByIds(userIds);
        if (CollUtils.isEmpty(users)){
            //throw new RuntimeException("用户不存在");
            log.info("没有提问的用户，即没有提问的问题:userIds {}",userIds);
        }
        //将list转为map<,>
        Map<Long, UserDTO> userMap = users.stream().collect(Collectors.toMap(UserDTO::getId, u -> u));
        /*if (query.getOnlyMine()){
            UserDTO questionUsers = userClient.queryUserById(userId);
        }*/
        ArrayList<QuestionVO> vos = new ArrayList<>();
        for (InteractionQuestion record : records) {
            //5.1copy相同属性
            QuestionVO vo = BeanUtil.copyProperties(record, QuestionVO.class);
            //5.2设置最新回答信息
            if (CollUtils.isNotEmpty(map)) {
                InteractionReply interactionReply = map.get(record.getLatestAnswerId());
                String content = interactionReply.getContent();
                if (content!=null) {
                    vo.setLatestReplyContent(content);
                }
                //5.5通过远程调用获取最近一次回答用户的昵称信息 如果设置了匿名，则不昵称设置为用户昵称
                UserDTO queryUserById = userClient.queryUserById(interactionReply.getUserId());
                if (queryUserById!=null && !interactionReply.getAnonymity()){
                    vo.setLatestReplyUser(queryUserById.getName());
                }
            }
            //5.6设置提问者昵称和头像 如果设置了匿名，则不昵称设置为用户昵称和头像
            if (CollUtils.isNotEmpty(userMap) && !record.getAnonymity()) {
                //5.3设置提问者昵称
                vo.setUserName(userMap.get(record.getUserId()).getUsername());
                //5.4设置提问者头像
                vo.setUserIcon(userMap.get(record.getUserId()).getIcon());
            }
            vos.add(vo);
        }
        log.info("封装vo返回对象 vos {}",vos);
        //6.封装vo返回对象
        return PageDTO.of(page, vos);
    }

    @Override
    public QuestionVO getQuestionById(Long id) {
        //1.判断id是否为空
        if (id==null){
            throw new BadRequestException("id不能为空");
        }
        //2.根据id查询互动问题表
        InteractionQuestion question = this.getById(id);
        if (question==null){
            throw new BadRequestException("互动问题不存在");
        }
        //3.获取表中的userId远程调用用户微服务查询用户昵称和头像 如果设置了匿名，则不昵称设置为用户昵称和头像
        QuestionVO vo = BeanUtil.copyProperties(question, QuestionVO.class);
        if (!question.getAnonymity()){
            UserDTO userDTO = userClient.queryUserById(question.getUserId());
            if (userDTO!=null){
                vo.setUserName(userDTO.getName());
                vo.setUserIcon(userDTO.getIcon());
            }
        }
        //返回vo
        return vo;
    }

    @Override
    public PageDTO<QuestionAdminVO> queryAdminQuestionPage(QuestionAdminPageQuery query) {
        //1.通过es查询前端传来的课程名称得到互动问题id集合
        List<Long> cIds=null;
        if (query.getCourseName()!=null) {
            cIds = searchClient.queryCoursesIdByName(query.getCourseName());
            if (CollUtils.isEmpty(cIds)){
                throw new BadRequestException("输入课程名称不存在");
            }
        }
        //2.分页查询互动问题表得到互动问题集合
        Page<InteractionQuestion> page = this.lambdaQuery()
                .in(CollUtils.isNotEmpty(cIds), InteractionQuestion::getCourseId, cIds)
                .eq(InteractionQuestion::getHidden, false)
                .eq(query.getStatus() != null, InteractionQuestion::getStatus, query.getStatus())
                .gt(query.getBeginTime() != null, InteractionQuestion::getCreateTime, query.getBeginTime())
                .lt(query.getEndTime() != null, InteractionQuestion::getCreateTime, query.getEndTime())
                .page(query.toMpPageDefaultSortByCreateTimeDesc());
        List<InteractionQuestion> records = page.getRecords();
        if (CollUtils.isEmpty(records)){
            return PageDTO.empty(page);
        }
        //2.1通过stream流获取课程id集合，可以重复用list
        List<Long> cids = records.stream().map(InteractionQuestion::getCourseId).collect(Collectors.toList());
        //3.远程查询课程信息
        List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(cids);
        if (CollUtils.isEmpty(simpleInfoList)){
            throw new BadRequestException("课程不存在");
        }
        //3.1通过stream流将simpleInfoList转为map集合map<id,CourseSimpleInfoDTO>
        Map<Long, CourseSimpleInfoDTO> map = simpleInfoList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, v -> v));
        //4远程调用分类接口查询分类信息 后面要用来查询三级分类名称
        List<CategoryBasicDTO> level = categoryClient.getAllOfOneLevel();

        //5.远程查询查询章节信息，获取章节名称和小节名称
          //5.1通过stream流获取章节id集合，可以重复用list
        List<Long> collect = records.stream().map(InteractionQuestion::getChapterId).collect(Collectors.toList());
        List<CataSimpleInfoDTO> dtos = catalogueClient.batchQueryCatalogue(collect);
        if (CollUtils.isEmpty(dtos)){
            throw new BadRequestException("章节不存在");
        }
        //5.2 通过stream流将dtos转为map集合map<id,CataSimpleInfoDTO>
        Map<Long, String> map1 = dtos.stream().collect(Collectors.toMap(CataSimpleInfoDTO::getId, CataSimpleInfoDTO::getName));

        // 6.封装vo返回对象
        ArrayList<QuestionAdminVO> list = new ArrayList<>();
        for (InteractionQuestion record : records) {
            //1.封装共有属性
            QuestionAdminVO vo = BeanUtil.copyProperties(record, QuestionAdminVO.class);
            if (CollUtils.isNotEmpty(map)){
                //2.封装课程名称，categoryName
                CourseSimpleInfoDTO dto = map.get(record.getCourseId());
                if (dto!=null){
                    vo.setCourseName(dto.getName());
                    String categoryNames = categoryCache.getCategoryNames(List.of(dto.getFirstCateId(), dto.getSecondCateId(), dto.getThirdCateId()));
                    vo.setCategoryName(categoryNames);
                }
                /*if (dto != null && dto.getFirstCateId() != null && dto.getSecondCateId() != null && dto.getThirdCateId() != null) {
                    String c1 = "";
                    String c2 = "";
                    String c3 = "";
                    for (CategoryBasicDTO basicDTO : level) {
                        if (basicDTO.getId().equals(dto.getFirstCateId())){
                            c1=basicDTO.getName();
                        }
                        if (basicDTO.getId().equals(dto.getSecondCateId())){
                            c2=basicDTO.getName();
                        }
                        if (basicDTO.getId().equals(dto.getThirdCateId())){
                            c3=basicDTO.getName();
                        }
                    }
                            vo.setCategoryName(c1 + "/" + c2 + "/" + c3);
                }*/
            }
                //3.封装章节名称，小节名称
           /* String name = map1.get(record.getChapterId()).getName();
            if (name!=null){
                vo.setChapterName(name);
            }
            String SectionName = map1.get(record.getSectionId()).getName();
            if (SectionName!=null) {
                vo.setSectionName(SectionName);
            }*/
            vo.setChapterName(map1.getOrDefault(record.getChapterId(), ""));
            vo.setSectionName(map1.getOrDefault(record.getSectionId(), ""));
            //4.封装用户昵称
            if (!record.getAnonymity()){
                UserDTO userDTO = userClient.queryUserById(record.getUserId());
                if (userDTO!=null){
                    vo.setUserName(userDTO.getUsername());
                }
            }
            list.add(vo);
        }
        return PageDTO.of(page, list);
    }

    @Override
    public void deleteMyQuestion(Long id) {
        //1.判健壮性判断
        if (id==null){
            throw new BadRequestException("输入的id有误");
        }
        //2.获取当前登录用户id
        Long userId = UserContext.getUser();
       //3.判断当前登录用户id是否与问题表中的userId一致
        InteractionQuestion question = this.getById(id);
        if (!userId.equals(question.getUserId())){
            throw new BadRequestException("不能删除他人问题");
        }
        //4.删除问题
        boolean success = this.removeById(id);
        if (!success){
            throw new DbException("删除失败");
        }
    }

    @Override
    public void updateQuestionStatus(Long id, Boolean hidden) {
        if (id==null){
            throw new BadRequestException("输入的id有误");
        }
        boolean update = this.lambdaUpdate()
                .eq(InteractionQuestion::getId, id)
                .set(InteractionQuestion::getHidden, hidden)
                .update();
        if (!update){
            throw new DbException("更新失败");
        }
    }

    @Override
    public QuestionAdminVO getAdminQuestionById(Long id) {
        if (id==null){
            throw new BadRequestException("输入的id有误");
        }
        //1.查询问题
        InteractionQuestion question = this.getById(id);
        if (question==null || question.getHidden()){
            return null;
        }

        //2.调用远程接口查询课程信息
        CourseFullInfoDTO courseInfoById = courseClient.getCourseInfoById(question.getCourseId(), true, true);
        if (courseInfoById==null){
            throw new BadRequestException("课程不存在");
        }
        //3.调用远程接口查询章节信息
        List<CataSimpleInfoDTO> infoDTOS = catalogueClient.batchQueryCatalogue(List.of(question.getChapterId()));
        if (CollUtils.isEmpty(infoDTOS)){
            throw new BadRequestException("章节不存在");
        }
        List<CataSimpleInfoDTO> infoDTOS1 = catalogueClient.batchQueryCatalogue(List.of(question.getSectionId()));
        if (CollUtils.isEmpty(infoDTOS1)){
            throw new BadRequestException("小节不存在");
        }
        //4.调用远程接口查询分类信息
        String categoryNames = categoryCache.getCategoryNames(List.of(courseInfoById.getFirstCateId(), courseInfoById.getSecondCateId(), courseInfoById.getThirdCateId()));
        //5.调用远程接口查询用户信息
        UserDTO userById = userClient.queryUserById(question.getUserId());
        //6.封装vo返回对象
        QuestionAdminVO vo = BeanUtil.copyProperties(question, QuestionAdminVO.class);
        vo.setTeacherName(courseInfoById.getTeacherIds().get(0).toString());
        vo.setUserName(userById.getUsername());
        vo.setCategoryName(categoryNames);
        vo.setCourseName(courseInfoById.getName());
        vo.setChapterName(infoDTOS.get(0).getName());
        vo.setSectionName(infoDTOS1.get(0).getName());
        //7.将问题是否查看改为一查看
         this.lambdaUpdate()
                .eq(InteractionQuestion::getId, id)
                .set(InteractionQuestion::getStatus, QuestionStatus.CHECKED)
                .update();
        return vo;
    }
}





























